package com.huluobo.jetpackkotlindemo.coroutine

import android.os.AsyncTask
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import com.huluobo.jetpackkotlindemo.databinding.ActivityCoroutineBinding
import com.huluobo.jetpackkotlindemo.viewbinding.BaseActivity
import kotlinx.coroutines.*
import okhttp3.Dispatcher

/**
 * Created by lc on 2022/12/16.
 * 协程
 * ANR:应用程序无响应,一般来讲都是在主线程处理了耗时操作,避免这种操作基本上都是通过创建子线程来实现
 * 在android中哪些可以执行异步任务:Handler,AsyncTask,Runnable
 * 每一个Application都是一个进程,每一个进程中有很多线程,协程可以看做线程中的线程,处理的也是同步或者异步任务
 * 协程是一种并发设计模式
 * 协程中有3种形式来保证作用域,使用作用域来保证协程的生命周期
 */
class CoroutineActivity : BaseActivity<ActivityCoroutineBinding>() {
    override fun getViewBinding(): ActivityCoroutineBinding =
        ActivityCoroutineBinding.inflate(layoutInflater)

    private val job = Job()//工作对象
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

//        //创建是个运行在IO线程的协程
//        //顶级协程,一般在项目中我们不会这么去用
//        val job = GlobalScope.launch(Dispatchers.IO) {
//            Log.i("TagA", "当前线程:" + Thread.currentThread().name)
//        }
//
//        //取消协程工作
//        job.cancel()
//        //创建的是一个在主线程当中的协程
//        GlobalScope.launch(Dispatchers.Main) {
//            Log.i("TagA", "当前线程:" + Thread.currentThread().name)
//        }

        //CoroutineScope在项目中比较常用
        //async

        CoroutineScope(job).launch {
//            //处理相应的逻辑
//            val result = async {
//                try {
//                    //模拟耗时操作
//                    delay(3000)
//                    "运算结果:" + 3 / 0
//                } catch (e: Exception) {
//                    "结果异常"
//                }
//
//            }.await()
//            Log.i("TagA", result)

            val startTime = System.currentTimeMillis()
            val result = async {
                delay(2000)
                "操作成功"
            }

            val result2 = async {
                delay(1000)
                "获取成功"
            }
            Log.i("TagA", "执行结果:${result.await()}-${result2.await()}")
            val endTime = System.currentTimeMillis()
            Log.i("TagA", "执行时间:" + (endTime - startTime))
            //出现执行了3秒的过程,因为result1执行完成之后,会直接执行result2,会造成线程阻塞,所以时间会产生相加
            //程序是按照上下的顺序来执行的,当我在过程中调用await时,会造成当前线程阻塞,所以是同步执行,造成结果的时间会叠加在一起
            //如果在结果中调用await,这时是异步进行,这样不会造成时间的叠加
        }

        //withContext 挂起函数
        //什么是挂起
        CoroutineScope(job).launch {
            loadData()
        }

        CoroutineScope(job).launch {
            //Dispatchers.IO 常用与耗时操作,比如网络请求,文件读写等
            //Dispatchers.Main 表示程序在主线程中执行,所以在开启协程时,他的代码不一定是在自线程中执行的,可以进行切换
            //Dispatchers.Default 表示用计算密集型任务
            val result = withContext(Dispatchers.IO) {
                delay(2000)
                "操作成功"
            }
            Log.i("TagA", "result:$result")
        }

        loadDataFormNetWork()
    }

    //系统并不知道一个方法是否会在协程中运行,所以需要添加suspend来提示其他程序员(开发者),当前方法需要放到协程中调用
    private suspend fun loadData() {
        delay(2000)//是一个挂起函数,挂起函数必须放在协程的作用域中
        Log.i("TagA", "-----loadData------")
    }

    //使用CoroutineScope开启了一个Main的协程,通过withContext开启了一个IO协程,当withContext结束之后,会继续回到Main协程中执行UI的代码
    private fun loadDataFormNetWork() {
//        Thread {
//            //执行网络请求,结果回调
//            runOnUiThread {
//                //切换到UI线程
//            }
//        }
        CoroutineScope(job).launch(Dispatchers.Main) {
            val result = getResult()
            showUI(result)
        }
    }

    //使用挂起来处理线程的嵌套
    private suspend fun getResult() =
        withContext(Dispatchers.IO) {
            delay(2000)
            "获取网络成功"
        }

    private fun showUI(result: String) {
        mViewBinding.tvCenter.text = result
    }

}